﻿using System.Text.Json;
using Digitalmes.Domain;
using Digitalmes.Scada.Configuration;
using Digitalmes.Scada.Events;
using Digitalmes.Scada.Models;
using Digitalmes.Scada.Services;

namespace Digitalmes.Scada.Handlers;

/// <summary>
/// 扫关键物料处理。
/// </summary>
internal sealed class ScanBarcodeHandler : AbstractHandler, ITransientDependency
{
    private readonly IEventPublisher _eventPublisher;
    private readonly IScanBarcodeService _scanService;
    private readonly ILogger _logger;

    public ScanBarcodeHandler(
        IEventPublisher eventPublisher,
        IScanBarcodeService scanService, 
        ILogger<ScanBarcodeHandler> logger)
    {
        _eventPublisher = eventPublisher;
        _scanService = scanService;
        _logger = logger;
    }

    public override async Task<HandleResult> HandleAsync(RequestMessage message, CancellationToken cancellationToken = default)
    {
        var barcode = message.GetString(TagDefine.PLC_Scan_Barcode);

        // 请求日志
        _logger.LogInformation("[扫码上料请求] {Barcode}, 工位：{OpCode}，数据：{Message}",
            barcode ?? "",
            message.Schema.TagGroupName,
            JsonSerializer.Serialize(message.Values.Select(s => new { s.TagName, s.Address, s.Value })));

        if (string.IsNullOrWhiteSpace(barcode))
        {
            return LogAndReturn(ErrCode.E1301, message.Schema.TagGroupName!);
        }

        int? step = message.GetData(TagDefine.PLC_Scan_Step)?.GetInt();

        ScanInput input = new()
        {
            LineCode = message.Schema.ChannelName,
            OpCode = message.Schema.TagGroupName,
            Barcode = barcode,
            Step = step ?? 0,
        };

        try
        {
            var result = await _scanService.ScanAsync(input);

            // 响应日志
            string logCallbackItems = result.CallbackItems != null ? JsonSerializer.Serialize(result.CallbackItems) : "[]";
            _logger.LogInformation("[扫码上料响应数据] {Barcode}, 工位：{OpCode}，状态: {State}, 消息: [{InnerErrorCode}] {ErrMessage}; 回调值: {CallbackItems}",
                barcode,
                message.Schema.TagGroupName,
                result.State.ToString(),
                result.InnerErrorCode.ToString(),
                result.GetErrorMessage(),
                logCallbackItems);

            // 发布产品存档后处理事件
            await _eventPublisher.Publish(new AfterScanBarcodeEvent
            {
                LineCode = input.LineCode,
                OpCode = input.OpCode,
                Barcode = input.Barcode,
                Step = input.Step,
                State = result.State,
                ErrorMessage = result.GetErrorMessage(),
                InnerErrorCode = result.InnerErrorCode,
                Target = result.Target,
            }, PublishStrategy.ParallelNoWait, cancellationToken);

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "[扫码上料服务处理异常] {Barcode}, 工位：{OpCode}",
                barcode,
                message.Schema.TagGroupName);
            return HandleResult.Error();
        }
    }

    private HandleResult LogAndReturn(ErrCode errCode, string opCode)
    {
        var result = HandleResult.Error(errCode);
        _logger.LogWarning("[扫码上料响应数据] 工位：{OpCode}，状态: {State}, 消息: [{InnerErrorCode}]-{ErrMessage}",
                opCode,
                result.State.ToString(),
                result.InnerErrorCode.ToString(),
                result.GetErrorMessage());

        return result;
    }
}
